﻿ #include "modbus_uart.h"
#include "ui_modbus_uart.h"
#include <string>
#include <QStandardItemModel>
#include <QTableView>
#include "QDateTime"
#include <QTime>
#include <QDataStream>
#include <QDebug>
#include <qfiledialog.h>



quint16 modbus_uart::crc16ForModbus(const QByteArray &data,int flag)
{
    static const quint16 crc16Table[] =
    {
        0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241,
        0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440,
        0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40,
        0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841,
        0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40,
        0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41,
        0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641,
        0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040,
        0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240,
        0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441,
        0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41,
        0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840,
        0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41,
        0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40,
        0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640,
        0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041,
        0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240,
        0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441,
        0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41,
        0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840,
        0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41,
        0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40,
        0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640,
        0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041,
        0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241,
        0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440,
        0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40,
        0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841,
        0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40,
        0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41,
        0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641,
        0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040
    };

    quint8 buf;
    quint16 crc16 = 0xFFFF;

    for ( auto i = 0; i < data.size()-2; ++i )
    {
        buf = data.at( i ) ^ crc16;
        crc16 >>= 8;
        crc16 ^= crc16Table[ buf ];
    }

   auto crcl = crc16&0xFF; //crc低位
   auto crch = crc16>>8;//crc高位
   auto crc161=0xFFFF;
   crc161 = (((crc161&0x0)|crcl)<<8)|(crch);
   if(flag)
   {
    return crc16;
   }
   else
   {
    return crc161;
   }
}

modbus_uart::modbus_uart(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::modbus_uart)
{
    ui->setupUi(this);


    ui->send_msg->setVisible(false);//0f和10功能组合帧发送按钮隐藏
    ui->coilsetepbtn->setVisible(false);//0f参数按钮隐藏
    ui->regsetupbtn->setVisible(false);//10参数按钮隐藏
    ui->reg_LineEdit->setVisible(false);//寄存器输入框隐藏
    ui->labelreg->setVisible(false);//寄存器标签隐藏

    init();   //初始化

    connect(ui->GN_combox,SIGNAL(currentIndexChanged(QString)),this,SLOT(hide_SLOTS()));

    System_uart_init();//串口初始化函数

}

//主窗体初始化
void modbus_uart::init()
{

    //显示当前时间
    m_timer = new QTimer(this);
    connect(m_timer, SIGNAL(timeout()), this, SLOT(timerShow()));
    m_timer->setInterval(1000);
    m_timer->start();

    m_resendtimer = new QTimer(this);
    connect(m_resendtimer, SIGNAL(timeout()), this, SLOT(resendShow()));
    m_resendtimer->setInterval(3000);

    connect(this,&modbus_uart::packageSartc,mb_msg,&modbus_uart::packageSartc,Qt::QueuedConnection);

    //限制起时地址
    connect(ui->start_ad_LineEdit,&QLineEdit::textChanged,[=](){
        if(ui->start_ad_LineEdit->text().toInt()+ui->coil_LineEdit->text().toInt()>65536)
        {
            QMessageBox::warning(this,"提示","请检查起时地址和数量是否合法！",QMessageBox::Ok,QMessageBox::NoButton);
            ui->start_ad_LineEdit->clear();
        }
    });

    connect(ui->coil_LineEdit,&QLineEdit::textChanged,[=](){
        if(ui->start_ad_LineEdit->text().toInt()+ui->coil_LineEdit->text().toInt()>65536)
        {
            QMessageBox::warning(this,"提示","请检查起时地址和数量是否合法！",QMessageBox::Ok,QMessageBox::NoButton);
            ui->coil_LineEdit->clear();
        }
    });

    //限制从机地址
    connect(ui->slave_LineEdit,&QLineEdit::textChanged,[=](){
        if(ui->slave_LineEdit->text().toInt()>247||ui->slave_LineEdit->text().toInt()<1)
        {
            QMessageBox::warning(this,"提示","请检查从机地址是否合法！",QMessageBox::Ok,QMessageBox::NoButton);
            ui->slave_LineEdit->clear();
        }
    });

    //限制线圈数量和寄存器数量
    if(ui->GN_combox->currentIndex()==0)
    {
        //限制线圈个数为2000
        connect(ui->coil_LineEdit,&QLineEdit::textChanged,[=](){
            if(ui->coil_LineEdit->text().toInt()>2000||ui->coil_LineEdit->text().toInt()<1)
            {
                QMessageBox::warning(this,"提示","请检查线圈个数是否正确",QMessageBox::Ok,QMessageBox::NoButton);
                ui->coil_LineEdit->clear();
            }
        });
    }

    connect(ui->start_ad_LineEdit,&QLineEdit::textChanged,[=]{
       if(ui->start_ad_LineEdit->text().toInt()>65535)
       {
            QMessageBox::warning(this,"提示","请检查起时地址是否合法！",QMessageBox::Ok,QMessageBox::NoButton);
            ui->start_ad_LineEdit->clear();
       }
    });


    //表格初始化
    table_dataInit();
    readseting = new QSettings("Data.ini", QSettings::IniFormat);
    ReadOutIniData();
}


void modbus_uart::resendShow()
{
    resendNumber++;
    if(resendNumber<4)
    {
        QDateTime current_date_time =QDateTime::currentDateTime();
        QString current_date =current_date_time.toString("yyyy.MM.dd hh:mm:ss");
        ui->display_TextEdit->append(current_date+"从站无响应！");
        ui->display_TextEdit->append("第"
                              + QString::number(resendNumber)
                              + "次重新发送报文\n");
        Uart_Objects.write(resenddata);
    }
    else
    {
        resendNumber=0;
        ui->display_TextEdit->append("3次重传无效，从站无响应!\n");
        m_resendtimer->stop();
    }
}

//更新寄存器表
void modbus_uart::Updateregister(quint16 num, quint16 satrtaddr,QVector<quint16> bar)
{
    ui->tableregs->blockSignals(true);
    for(int i = satrtaddr,k=0; k < num;k++,i++)
    {
      ui->tableregs->setItem(1,i,new QTableWidgetItem(QString("%1").arg(bar[k])));
      ui->tableregs->item(1,i)->setTextAlignment(Qt::AlignHCenter|Qt::AlignVCenter);
    }
    ui->tableregs->blockSignals(false);
    bar.clear();
}

//更新线圈表
void modbus_uart::Updatecoil(quint16 num, quint16 satrtaddr, QString bac)
{
    ui->table_coil->blockSignals(true);
    for(int i = satrtaddr,k=0; k < num;k++,i++)
    {
        //在线圈数据表中显示数据
        QString data;
        if(bac[k] == '1')
        {
            data ="1";
        }
        else
        {
            data ="0";
        }
        ui->table_coil->setItem(1,i,new QTableWidgetItem(data));
        ui->table_coil->item(1,i)->setTextAlignment(Qt::AlignHCenter|Qt::AlignVCenter);
    }
    ui->table_coil->blockSignals(false);
    bac.clear();
}

void modbus_uart::wirtTablec(quint16 num, quint16 satrtaddr,QString bac)
{
    ui->table_coil->blockSignals(true);
    for(int i = satrtaddr,k=0; k < num;k++,i++)
    {
        //在线圈数据表中显示数据
        QString data;
        if(bac[k] == '1')
        {
            data ="1";
        }
        else
        {
            data ="0";
        }
        ui->table_coil->setItem(1,i,new QTableWidgetItem(data));
        ui->table_coil->item(1,i)->setTextAlignment(Qt::AlignHCenter|Qt::AlignVCenter);
    }
    ui->table_coil->blockSignals(false);
    bac.clear();
}

//更新寄存器表
void modbus_uart::wirtTabler(quint16 num, quint16 satrtaddr,QVector<quint16> bar)
{
    ui->tableregs->blockSignals(true);
    for(int i = satrtaddr,k=0; k < num;k++,i++)
    {
      ui->tableregs->setItem(1,i,new QTableWidgetItem(QString("%1").arg(bar[k])));
      ui->tableregs->item(1,i)->setTextAlignment(Qt::AlignHCenter|Qt::AlignVCenter);
    }
    ui->tableregs->blockSignals(false);
    bar.clear();
}

modbus_uart::~modbus_uart()
{
    delete ui;
}

//系统串口初始化
void modbus_uart::System_uart_init()
{
    UART_Flush_SLOTS();//检测系统可用的串口
//信号和槽函数
    connect(ui->open_uart,&QPushButton::clicked,this,&modbus_uart::UART_OPEN_SLOTS); //串口打开
    connect(ui->close_uart,&QPushButton::clicked,this,&modbus_uart::UART_CLOSE_SLOTS);//串口关闭
    connect(ui->write_data,&QPushButton::clicked,this,&modbus_uart::UART_send_SLOTS);//串口发送数据
    connect(ui->Flush_UART,&QPushButton::clicked,this,&modbus_uart::UART_Flush_SLOTS);//刷新可用串口
    connect(ui->setupbtn,&QPushButton::clicked,this,&modbus_uart::UART_setup_SLOTS);//刷新可用串口

    connect(&Uart_Objects,&QSerialPort::readyRead,[=]()
    {
           uart_Receive_time.start(ui->receive_time_spinBox->value());
    });//串口接收数据
    connect(&Uart_Objects,&QSerialPort::errorOccurred,this,&modbus_uart::UART_eerom_SLOTS);//串口出现错误
    connect(ui->AutoSend_checkBox,&QCheckBox::stateChanged,this,&modbus_uart::UART_time_run_SLOTS);  //定时器启动/停止 槽函数
    connect(&uart_time, SIGNAL(timeout()), this, SLOT(UART_time_SLOTS()));  //定时器信号和槽函数
    connect(&uart_Receive_time, &QTimer::timeout,[=](){
    uart_Receive_time.stop();
    UART_receive_SLOTS();
    });  //串口接收数据延时

    //connect(ui->lineEdit_data,&QLineEdit::editingFinished, this, &modbus_uart::UART_lineEdit_data_SLOTS);  //数据输入完成槽函数

}



//字节数组转16进制字符串
void ByteToHexString(QString &str, QByteArray &ba)
{
     // str= ba.toHex();//直接转换中间没有空格
    QString strs = ba.toHex().toUpper();//直接转换中间没有空格
    for(int i=0;i<strs.length();i+=2)
    {
        QString str_1 = strs.mid (i,2);
        str += str_1;
        str += " ";
    }
}

//串口打开事件
void modbus_uart::UART_OPEN_SLOTS(bool )
{

    ui->Baud_comboBox->setEnabled(false);
    ui->data_bit_comboBox->setEnabled(false);
    ui->verify_comboBox->setEnabled(false);
    ui->stop_comboBox->setEnabled(false);
    ui->come_comboBox->setEnabled(false);
    switch (ui->data_bit_comboBox->currentIndex()  ){//数据位
      case 0: Uart_Objects.setDataBits(QSerialPort::Data8); break;
      case 1: Uart_Objects.setDataBits(QSerialPort::Data7); break;
      case 2: Uart_Objects.setDataBits(QSerialPort::Data6); break;
      case 3: Uart_Objects.setDataBits(QSerialPort::Data5);break;
      default: break;
    }

    switch (ui->verify_comboBox->currentIndex()  ){//校验位
      case 0: Uart_Objects.setParity(QSerialPort::NoParity);      break;
      case 1: Uart_Objects.setParity(QSerialPort::EvenParity);    break;
      case 2: Uart_Objects.setParity(QSerialPort::OddParity);     break;
      case 3: Uart_Objects.setParity(QSerialPort::SpaceParity);   break;
      case 4: Uart_Objects.setParity(QSerialPort::MarkParity);    break;
      case 5: Uart_Objects.setParity(QSerialPort::UnknownParity); break;
    default: break;
    }

    switch (ui->stop_comboBox->currentIndex()  ){//停止位
      case 0: Uart_Objects.setStopBits(QSerialPort::OneStop); break;
      case 1: Uart_Objects.setStopBits(QSerialPort::OneAndHalfStop); break;
      case 2: Uart_Objects.setStopBits(QSerialPort::TwoStop); break;
      case 3: Uart_Objects.setStopBits(QSerialPort::UnknownStopBits);break;
      default: break;
    }

    Uart_Objects.setPortName(ui->come_comboBox->currentText());//根据下拉框显示的内容  确定打开的串口
    switch (ui->Baud_comboBox->currentIndex()  ){//选择波特率
      case 0: Uart_Objects.setBaudRate(QSerialPort::Baud115200); break;
      case 1: Uart_Objects.setBaudRate(QSerialPort::Baud57600 ); break;
      case 2: Uart_Objects.setBaudRate(QSerialPort::Baud38400 ); break;
      case 3: Uart_Objects.setBaudRate(QSerialPort::Baud19200 ); break;
      case 4: Uart_Objects.setBaudRate(QSerialPort::Baud9600  ); break;
      case 5: Uart_Objects.setBaudRate(QSerialPort::Baud4800  ); break;
      case 6: Uart_Objects.setBaudRate(QSerialPort::Baud2400  ); break;
      case 7: Uart_Objects.setBaudRate(QSerialPort::Baud1200  ); break;
      default: break;
    }

    if(Uart_Objects.open(QIODevice::ReadWrite)==false)//打开串口
    {
       ui->sign_label->setText("串口打开失败");
       UART_RUN = false;//打开失败 标志位清零
    }else
    {
        ui->sign_label->setText("串口打开");
        UART_RUN = true;//打开成功 标志位置1
    }
}


quint16 BondTwoUint8ToUint16(quint8 preNum, quint8 afterNum)
{
    quint16 bondNum = (preNum << 8) | afterNum;
    return bondNum;
}

//字节反转函数
void byteReverse(QString &coils)
{
    // 定义临时字符变量
    QChar temp;

    for(int i=0; i < 4; i++)
    {
        temp = coils[i];        // 将第i个元素存入临时字符变量
        coils[i] = coils[8-i-1];  // 将第i个字符元素和第n-i-1个元素对调
        coils[8-i-1] = temp;    // 将临时字符变量的值赋给第n-i-1个元素
    }
}


QByteArray HexStringToByteArray(QString HexString)
 {
     bool ok;
     QByteArray ret;
     HexString = HexString.trimmed();
     HexString = HexString.simplified();
     QStringList sl = HexString.split(" ");

     foreach (QString s, sl) {
         if(!s.isEmpty()) {
             char c = s.toInt(&ok,16)&0xFF;
             if(ok){
                 ret.append(c);
             }else{
                 qDebug()<<"非法的16进制字符："<<s;
             }
         }
     }
     return ret;
 }

 QString ByteArrayToHexString(QByteArray &ba)
 {
     QDataStream out(&ba,QIODevice::ReadWrite);   //将str的数据 读到out里面去
     QString buf;
     while(!out.atEnd())
     {
         qint8 outChar = 0;
         out >> outChar;   //每次一个字节的填充到 outchar
         QString str =QString("%1").arg(outChar&0xFF,2,16,QLatin1Char('0')).toUpper() + QString(" ");   //2 字符宽度
         buf += str;
     }
     return buf;
 }

//hex发送判断同时在末尾加上CRC校验 同时串口发送
 void modbus_uart::str_add_CRC(QString str)
 {
     QByteArray array;
     qint64 num;

     if(ui->write_hex_checkBox-> isChecked()==true )//16进制发送选项被选中
     {
          QString str1,str2;
          bool ok;
          for (int i=0;i<str.length();i++)//遍历一遍  将空格和多余的字符 删除
          {
              if(str[i]!=' ')
              {
                  str2+=str[i];
                  qDebug()<<str[i];
              }
          }

          uchar *crc = new uchar(str2.length());//动态创建内存（不知道发送的16进制数据为多少位，所以使用动态内存）
          int ii=0;
          for (int i=0;i<str2.length();i+=2)//遍历 将数据转换成16进制
          {
                str1 += str2.mid(i,2).toInt(&ok,16);   //将“121314aaff”按照12、13、14、aa、ff十六进制数存到buffer里
                if(ui->write_CRC16_checkBox->isChecked()==true )//CRC16校验是否选中
                crc[ii] =str2.mid(i,2).toInt(&ok,16);
                  ii++;
          }

         if(ui->write_CRC16_checkBox->isChecked()==true )//CRC16校验是否选中
         {
             uint nun =  CRC16_Calc(crc,str1.length());//crc校验函数，注意返回的数据是16位数据
             str1+=nun>>8;//拼接字符串在字符串末尾添加CRC16校验位
               str1+=nun;
         }

           num = Uart_Objects.write(str1.toLatin1());//将转换好的hex数据通过串口发送输出
           if(num!=-1)
           {
               send_value=send_value+num;
           }

           delete crc;//发送完成，将动态分配的内存释放掉
     }

     else
     {
          array = str.toLocal8Bit().constData() ;//转换成GBK2312编码
          //array = data.toUtf8() ;//转换成UTF8编码
          num = Uart_Objects.write(array);//串口发送数据
          if(num!=-1)
          {
              send_value=send_value+num;
          }
      }
     ui->send_label->setText(QString("发送字节：""%1").arg(send_value));
 }


//表格初始化
 void modbus_uart::table_dataInit()
 {
     //设置表格
     QStringList TableHeader;
     TableHeader << "地址" << "数据";
     ui->table_coil->setVerticalHeaderLabels(TableHeader);
     ui->table_coil->setSelectionMode(QAbstractItemView::SingleSelection);
     ui->tableregs->setVerticalHeaderLabels(TableHeader);
     ui->tableregs->setSelectionMode(QAbstractItemView::SingleSelection);
     ui->tableregs->setEditTriggers(QAbstractItemView::NoEditTriggers);
     ui->table_coil->setEditTriggers(QAbstractItemView::NoEditTriggers);
 }

 //将ini文件中的数据取出来放到表格内
 void modbus_uart::ReadOutIniData(void)
 {
     for(int i = 0; i < (ADDRESS_MAX + 1); i++)
     {
         //地址设置
         QString adr =  "0X" + QString("%1").arg(i,4,16,QLatin1Char('0'));
         ui->table_coil->setItem(0,i, new QTableWidgetItem(QString(adr).toUpper()));
         ui->table_coil->item(0,i)->setTextAlignment(Qt::AlignHCenter|Qt::AlignVCenter);
         ui->tableregs->setItem(0,i, new QTableWidgetItem(QString(adr)));
         ui->tableregs->item(0,i)->setTextAlignment(Qt::AlignHCenter|Qt::AlignVCenter);
         //读出线圈数据
         QString coilData = readseting->value("Section" + QString::number(i+1) + "/coil").toString();
         //读出寄存器数据
         QString registerData = readseting->value("Section" + QString::number(i+1) + "/regi").toString();
         //在线圈数据表中显示数据
         ui->table_coil->setItem(1,i,new QTableWidgetItem(coilData));
         //设置表格内文字水平+垂直对齐
         ui->table_coil->item(1,i)->setTextAlignment(Qt::AlignHCenter|Qt::AlignVCenter);
         //在寄存器数据表中显示数据
         ui->tableregs->setItem(1,i,new QTableWidgetItem(registerData));
         //设置表格内文字水平+垂直对齐
         ui->tableregs->item(1,i)->setTextAlignment(Qt::AlignHCenter|Qt::AlignVCenter);
     }
 }

//串口发送数据槽函数
void modbus_uart::UART_send_SLOTS()
{
    QString data = ui->lineEdit_data->text();//获取输入框中的数据
    str_add_CRC(data);
}

//crc校验
uint  modbus_uart::CRC16_Calc(uchar *pBuf, uint uLen)
{
       uint crc = 0xffff;
       uint i;
       while(uLen--)
       {
           crc ^=(uint) *pBuf++;
           for(i=0; i<8; i++)
           {
               if(crc & 0x0001)
               {
                    crc = (crc >> 1) ^ 0xa001;
                }
               else
               {
                    crc = crc >> 1;
               }
           }
       }
       //CRC高低位转换
       uint crc_r = crc<<8;
       crc=crc>>8;
       crc = crc|crc_r;
       crc=crc&0xffff;
       return crc;
}

//串口接受数据槽函数
void modbus_uart::UART_receive_SLOTS()
{
    //缓存数组
    QByteArray array = Uart_Objects.readAll();
    QDateTime current_date_time =QDateTime::currentDateTime();
    QString current_date =current_date_time.toString("yyyy.MM.dd hh:mm:ss");

    receive_value += array.size();

    //显示接收的数据的所有的字节数
    ui->receive_label->setText(QString("接收字节：""%1").arg(receive_value));

    if(ui->receive_hex_checkBox->checkState() == Qt::Checked){//是否16进制显示
         QString msg;
          m_resendtimer->stop();
          resendNumber=0;
         msg = array.toHex(' ').append(' ').toUpper();
         // toHex(' ')返回16进制的编码并且使用' '作为16进制的分隔符号
         // append(' ') 在字符串最后面添加一个字符' '  .toUpper()将英文字符转换成大写

         //主机解析报文
         ParseResponseMessage(array);
          ui->display_TextEdit->append(msg+"\n");
          ui->display_TextEdit->append("从机回应               "+current_date+"\n");
    }else//字符显示
    {
          ui->display_TextEdit->setText(QString::fromLocal8Bit(array));//将二进制文件转换成本地编码（gbk2312）
          //ui->display_TextEdit->setText(QString(array));//默认是utf8编码
    }
}

//串口关闭槽函数
void modbus_uart::UART_CLOSE_SLOTS(bool)
{
   Uart_Objects.close();
   ui->sign_label->setText("串口未打开");
   ui->Baud_comboBox->setEnabled(true);
   ui->data_bit_comboBox->setEnabled(true);
   ui->verify_comboBox->setEnabled(true);
   ui->stop_comboBox->setEnabled(true);
   ui->come_comboBox->setEnabled(true);
}

//刷新可用串口槽函数
void modbus_uart::UART_Flush_SLOTS( )
{
   ui->come_comboBox->clear();//清除下拉列表框内容
   uart_info = QSerialPortInfo::availablePorts();//获取系统可用的串口
   qDebug()<< "系统可用串口数量为 "<<uart_info.count(); //输出系统可用串口数量（链表中的数量）

   for (int i=0;i<uart_info.count();i++)
   ui->come_comboBox->addItem(uart_info.value(i).portName()); //不带图
}

//时间显示
void modbus_uart::timerShow()
{
    QDateTime current_date_time =QDateTime::currentDateTime();
    QString current_date =current_date_time.toString("yyyy.MM.dd hh:mm:ss ddd");
    ui->time_line->setText(current_date);
}

//显示信息封装 利于调用
void modbus_uart::showmsg(QString msg)
{
     ui->display_TextEdit->append(msg+"\r\n");
}

//串口发生错误 槽函数
void modbus_uart::UART_eerom_SLOTS(int y )
{
        if(y!=0)//错误0 表示没有错误
        {
            int int_eeorm=Uart_Objects.error();//获取错误数据
            QString eerom1;//创建一个字符串
            switch (int_eeorm)
            {
                 case 1 : eerom1 = " 试图打开不存在的设备时发生错误。";   break;
                 case 2 : eerom1 = " 当另一个进程或用户没有足够的权限和凭据打开一个已经打开的设备时发生错误。";   break;
                 case 3 : eerom1 = " 试图打开此对象中已经打开的设备时发生错误。";   break;
                 case 4 : eerom1 = " 读取数据时由硬件检测到的奇偶校验错误。该值过时。我们强烈建议不要在新代码中使用它。";   break;
                 case 5 : eerom1 = " 读取数据时由硬件检测到的帧错误。该值过时。我们强烈建议不要在新代码中使用它。";   break;
                 case 6 : eerom1 = " 由硬件在输入线上检测到的中断状态。该值过时。我们强烈建议不要在新代码中使用它。";   break;
                 case 7 : eerom1 = " 写入数据时发生了一个I/O错误。";   break;
                 case 8 : eerom1 = " 读取数据时发生了一个I/O错误。";   break;
                 case 9 : eerom1 = " 一个I/O错误发生时，资源变得不可用，例如当设备被意外地从系统中删除。";   break;
                 case 10 : eerom1 = " 正在运行的操作系统不支持或禁止请求的设备操作。";   break;
                 case 11 : eerom1 = " 发生了一个未知的错误。";   break;
                 case 12 : eerom1 = " 发生超时错误。";   break;
                 case 13 : eerom1 = " 当执行的操作只有打开设备才能成功执行时，发生此错误。";   break;
            }
             QMessageBox::about(this,tr("串口打开失败"),eerom1 );//弹出提示框，并显示错误信息
        }
}


//定时器定时时间到达
void modbus_uart::UART_time_SLOTS( )
{
    if(UART_RUN == true)//打开成功 标志位置
    {
        UART_send_SLOTS();
    }
}

//定时器开启关闭函数
void modbus_uart::UART_time_run_SLOTS(bool run)
{
    if(run)
    {
        qDebug()<< "定时发送打开";
        uart_time.start(ui->time_spinBox->value());//根据输入框输入的值，控制定时器定时的时间
    } else
    {
       qDebug()<< "定时发送关闭 ";
       uart_time.stop();//关闭定时器
    }
}
//清除接收字节
void modbus_uart::on_receive_pushButton_clicked()
{
    receive_value = 0;
    ui->receive_label->setText(QString("接收字节：""%1").arg(receive_value));
    ui->display_TextEdit->clear();
}
//清除发送字节
void modbus_uart::on_send_pushButton_clicked()
{
    send_value = 0;
    ui->send_label->setText(QString("发送字节：""%1").arg(send_value));
}

//读取串口数据帧并处理
void modbus_uart::readMyComA(QByteArray temp)
{
    QDataStream out(&temp, QIODevice::ReadWrite);
    while (!out.atEnd()) {
        qint8 outChar = 0;
        out>>outChar;
        QString byte = QString("%1").arg(outChar&0xFF, 2, 16, QLatin1Char('0'));
        byte = byte.toUpper();
    }
}

//功能码01 03隐藏写入值和字节数
void modbus_uart::hide_SLOTS()
{
    //功能码为01 隐藏字节设置控件
    if(ui->GN_combox->currentIndex()==0)
    {
        ui->labelcoil->setVisible(true);
        ui->coil_LineEdit->setVisible(true);
        ui->labelstartaddrees->setVisible(true);
        ui->start_ad_LineEdit->setVisible(true);
        ui->labelslaveaddress->setVisible(true);
        ui->slave_LineEdit->setVisible(true);
        ui->labelcoil->setText("线圈个数:");
        ui->setupbtn->setVisible(true);
        ui->setupbtn->setText("发送");

        ui->send_msg->setVisible(false);//0f和10功能组合帧发送按钮隐藏
        ui->coilsetepbtn->setVisible(false);//0f参数按钮隐藏
        ui->regsetupbtn->setVisible(false);//10参数按钮隐藏
        ui->reg_LineEdit->setVisible(false);
        ui->labelreg->setVisible(false);
    }
    //功能码为03 隐藏字节设置控件
    else if (ui->GN_combox->currentIndex()==1)
    {
        ui->labelcoil->setVisible(true);
        ui->coil_LineEdit->setVisible(true);
        ui->labelstartaddrees->setVisible(true);
        ui->start_ad_LineEdit->setVisible(true);
        ui->labelslaveaddress->setVisible(true);
        ui->slave_LineEdit->setVisible(true);
        ui->labelcoil->setText("寄存器数量:");
        ui->setupbtn->setVisible(true);
         ui->setupbtn->setText("发送");
         ui->reg_LineEdit->setVisible(true);//寄存器输入框隐藏
         ui->labelreg->setVisible(true);//寄存器标签隐藏

         ui->send_msg->setVisible(false);
         ui->send_msg->setVisible(false);//0f和10功能组合帧发送按钮隐藏
         ui->coilsetepbtn->setVisible(false);//0f参数按钮隐藏
         ui->regsetupbtn->setVisible(false);//10参数按钮隐藏
         ui->labelcoil->setVisible(false);  //隐藏线圈
         ui->coil_LineEdit->setVisible(false);

         connect(ui->reg_LineEdit,&QLineEdit::textChanged,[=](){
             if(ui->reg_LineEdit->text().toInt()>125||ui->reg_LineEdit->text().toInt()<1)
             {
                 QMessageBox::warning(this,"提示","请检查寄存器个数是否正确",QMessageBox::Ok,QMessageBox::NoButton);
                 ui->reg_LineEdit->text().clear();
             }
         });
    }
    //功能码为10 显示字节设置控件
    else if (ui->GN_combox->currentIndex()==2)
    {
        //写入值输入框隐藏
        ui->coil_LineEdit->setVisible(false);
        ui->labelslaveaddress->setVisible(false);
        ui->labelstartaddrees->setVisible(false);
        ui->coilsetepbtn->setVisible(false);//0f参数按钮隐藏
        ui->reg_LineEdit->setVisible(false);//寄存器输入框隐藏
        ui->labelreg->setVisible(false);//寄存器标签隐藏
        //线圈lable隐藏
        ui->labelcoil->setVisible(false);
        //从机地址输入框隐藏
        ui->slave_LineEdit->setVisible(false);
        //起时地址输入框隐藏
        ui->start_ad_LineEdit->setVisible(false);
        ui->setupbtn->setVisible(false);
        ui->send_msg->setVisible(true);
        ui->regsetupbtn->setVisible(true);//10参数按钮隐藏

    }
    //功能码为0f 显示字节设置控件
    else if (ui->GN_combox->currentIndex()==3)
    {
        //写入值输入框隐藏
        ui->coil_LineEdit->setVisible(false);
        ui->labelslaveaddress->setVisible(false);
        ui->labelstartaddrees->setVisible(false);
        ui->reg_LineEdit->setVisible(false);//寄存器输入框隐藏
        ui->labelreg->setVisible(false);//寄存器标签隐藏
        //线圈lable隐藏
        ui->labelcoil->setVisible(false);
        //从机地址输入框隐藏
        ui->slave_LineEdit->setVisible(false);
        //起时地址输入框隐藏
        ui->start_ad_LineEdit->setVisible(false);
        ui->setupbtn->setText("设置参数");
        ui->send_msg->setVisible(true);
        ui->setupbtn->setVisible(false);
        ui->coilsetepbtn->setVisible(true);//0f参数按钮隐藏
        ui->regsetupbtn->setVisible(false);//10参数按钮隐藏
    }
}

//设置参数 发送字节
void modbus_uart::UART_setup_SLOTS()
{
    QByteArray data_01,data_03;

    //获取控件中整型数据
    quint8 str_gn = ui->GN_combox->currentText().toInt();
    quint8 str_slave = ui->slave_LineEdit->text().toInt();
    quint16 str_start = ui->start_ad_LineEdit->text().toInt();
    quint16 str_coil = ui->coil_LineEdit->text().toInt();
    quint16 str_reg = ui->reg_LineEdit->text().toInt();


    //选中功能码发送
    switch (ui->GN_combox->currentIndex())
    {
        //功能码01发送请求帧
        case 0:{
                    //从机地址
                    msgbuf[0]=str_slave;
                    //功能码
                    msgbuf[1]=str_gn;
                     //起始地址高位
                    msgbuf[2]=str_start>>8;
                    //起时地址低位
                    msgbuf[3]=str_start&0xFF;
                    //线圈最高位
                    msgbuf[4]=str_coil>>8;
                    //线圈最低位
                    msgbuf[5]=str_coil&0xff;
                    QByteArray crcba((char*)msgbuf,8);
                    quint16 crc16 = crc16ForModbus(crcba,CRC_FLAG);
                    //CRC校验高位
                    msgbuf[6] = crc16>>8;
                    //CRC校验低位
                    msgbuf[7] = crc16&0xFF;
                    QByteArray ba((char*)msgbuf,8);
                    requestMessage = ba;
                    if(str_slave==0||str_coil==0)
                    {
                        QMessageBox::warning(this,"错误","输入阈值中的数据");
                    }
                    else {
                        //串口发送
                        Uart_Objects.write(ba);
                        if(!Uart_Objects.isOpen())
                        {
                            QMessageBox::warning(this,"错误","请打开串口");
                        }
                        else {

                            QDateTime current_date_time =QDateTime::currentDateTime();
                            QString current_date =current_date_time.toString("yyyy.MM.dd hh:mm:ss");
                            msg =  msg = ba.toHex(' ').append(' ').toUpper();
                             ui->display_TextEdit->append(msg+"\n");
                             ui->display_TextEdit->append("主机发送              "+current_date+"\n");
                             resenddata = ba;
                             m_resendtimer->start();
                             resendNumber=0;
                        }
                    }

             break;
         }

         //功能码03发送请求帧
         case 1:
         {
                    //从站地址
                    msgbuf[0] =str_slave;
                    //功能码
                    msgbuf[1] = str_gn;
                    //起始地址高位
                    msgbuf[2] = str_start>>8;
                    //起始地址低位
                    msgbuf[3] = str_start&0xFF;
                    //寄存器数量高位
                    msgbuf[4] = str_reg>>8;
                    //寄存器数量地位
                    msgbuf[5] = str_reg&0xFF;
                    //CRC校验
                    QByteArray crcba((char*)msgbuf,8);
                    quint16 crc16 = crc16ForModbus(crcba,CRC_FLAG);
                    //CRC校验高位
                    msgbuf[6] = crc16>>8;
                    //CRC校验低位
                    msgbuf[7] = crc16&0xFF;
                    QByteArray ba((char*)msgbuf,8);
                    requestMessage = ba;
                    if(str_slave==0||str_reg==0)
                    {
                        QMessageBox::warning(this,"错误","输入阈值中的数据");
                    }
                    else {
                        //串口发送
                        Uart_Objects.write(ba);
                        if(!Uart_Objects.isOpen())
                        {
                            QMessageBox::warning(this,"错误","请打开串口");
                        }
                        else {
                            QDateTime current_date_time =QDateTime::currentDateTime();
                            QString current_date =current_date_time.toString("yyyy.MM.dd hh:mm:ss");
                            msg =  msg = ba.toHex(' ').append(' ').toUpper();
                            ui->display_TextEdit->append(msg+"\n");
                            ui->display_TextEdit->append("主机发送              "+current_date+"\n");
                            resenddata = ba;
                            m_resendtimer->start();
                            resendNumber=0;
                        }
                    }
         }
             break;
    default: break;
    }
}

//0f 10 功能码请求帧封装开始函数
void modbus_uart::packageSartc(quint8 addr,quint8 funcode,quint16 startaddr,quint16 num,QByteArray ba,QVector<quint16>regs)
{
    switch(funcode)
    {
    case  15:funCode0f(addr,startaddr,num,ba);
        break;
    case  16:funCode10(addr,startaddr,regs);
        break;
    }
}

//10功能码封装
void modbus_uart::funCode10(quint8 addr,quint16 startaddr,QVector<quint16> addrvalue)
{
    //计算数据大小
    quint16 num= addrvalue.size();
    //从站地址
    msgbuf[0] =addr;
    //功能码
    msgbuf[1] = 0x10;
    //起始地址高位
    msgbuf[2] = startaddr>>8;
    //起始地址低位
    msgbuf[3] = startaddr&0xFF;
    //寄存器数量高位
    msgbuf[4] = num>>8;
    //寄存器数量地位
    msgbuf[5] = num&0xFF;
    //字节计数
    msgbuf[6] =(quint8)(num*2);
    //数据
    for(quint8 k=7,z=0;z<num;z++)
    {
        msgbuf[k++] = (quint16)addrvalue.at(z)>>8;
        msgbuf[k++] = (quint16)addrvalue.at(z)&0xFF;
    }
    //CRC校验
    QByteArray crcba((char*)msgbuf,9+(quint8)(num*2));
    quint16 crc16 = crc16ForModbus(crcba,CRC_FLAG);
    //CRC校验高位
    msgbuf[7+num*2] = crc16>>8;
    //CRC校验低位
    msgbuf[8+num*2] = crc16&0xFF;
    QByteArray ba((char*)msgbuf,9+(quint8)(num*2));
    requestMessage = ba;
//    emit package_over(ba);
    memset(msgbuf,0,9+(quint8)(num*2));

    Uart_Objects.write(ba);

    WirteRegsPackMsgToShow(startaddr,num,ba);

    if(!Uart_Objects.isOpen())
    {
        QMessageBox::warning(this,"错误","请打开串口");
    }
    else {
        QDateTime current_date_time =QDateTime::currentDateTime();
        QString current_date =current_date_time.toString("yyyy.MM.dd hh:mm:ss");
        msg =  msg = ba.toHex(' ').append(' ').toUpper();
        ui->display_TextEdit->append(msg+"\n");
        ui->display_TextEdit->append("主机发送              "+current_date+"\n");
        resenddata = ba;
        m_resendtimer->start();
        resendNumber=0;
    }
 //   addrvalue.clear();
}


//0f功能码封装
void modbus_uart::funCode0f(quint8 addr,quint16 startaddr,quint16 num,QByteArray bas)
{
    QString msg;
    quint8 sizenum=bas.size();
    //从站地址
    msgbuf[0] =addr;
    //功能码
    msgbuf[1] = 0x0f;
    //起始地址高位
    msgbuf[2] = startaddr>>8;
    //起始地址低位
    msgbuf[3] = startaddr&0xFF;
    //线圈数量高位
    msgbuf[4] = num>>8;
    //线圈数量地位
    msgbuf[5] = num&0xFF;
    //字节计数
    msgbuf[6] =(quint8)(sizenum);
    //数据
    for(quint16 i=0;i<sizenum;i++)
    {
        msgbuf[7+i] = (quint8)bas.at(i);
    }
    //CRC校验
    QByteArray crcba((char*)msgbuf,9+(quint8)(sizenum));
    quint16 crc16 = crc16ForModbus(crcba,CRC_FLAG);
    //CRC校验高位
    msgbuf[7+sizenum++] = crc16>>8;
    //CRC校验低位
    msgbuf[7+sizenum++] = crc16&0xFF;
    QByteArray ba((char*)msgbuf,7+(quint8)(sizenum));
    requestMessage = ba;
    Uart_Objects.write(ba);

    WirteCoilPackMsgToShow(startaddr,num,ba);

    if(!Uart_Objects.isOpen())
    {
        QMessageBox::warning(this,"错误","请打开串口");
    }
    else {
        QDateTime current_date_time =QDateTime::currentDateTime();
        QString current_date =current_date_time.toString("yyyy.MM.dd hh:mm:ss");
        msg =  msg = ba.toHex(' ').append(' ').toUpper();
        ui->display_TextEdit->append(msg+"\n");
        ui->display_TextEdit->append("主机发送              "+current_date+"\n");
        resenddata = ba;
        m_resendtimer->start();
        resendNumber=0;
    }
    memset(msgbuf,0,7+(quint8)(sizenum));
}

//10和0f功能发送报文
void modbus_uart::on_send_msg_clicked()
{
    if(!uartIsOpen)
    {
        switch (m_code)
        {
            case 15:
            {
                if(!coildata.isEmpty())
                {
                    emit packageSartc(inf.at(0),15,inf.at(1),inf.at(2),coildata,regdata);
                }
                else
                {
                    QMessageBox::warning(this,"错误","请设置参数");
                }
                break;
            }
        case 16:
        {
            if(!regdata.isEmpty())
            {
                emit packageSartc(inf.at(0),16,inf.at(1),inf.at(2),coildata,regdata);
            }
            else
            {
                QMessageBox::warning(this,"错误","请设置参数");
            }
            break;
        }
        default:
            QMessageBox::warning(this,"错误","请设置参数");
            break;
        }
    }
}


//0f功能码参数设置
void modbus_uart::on_coilsetepbtn_clicked()
{
    dialog = new Dialog(this);
    m_code = 0x0f;
    int flag = dialog->exec();
    if(!flag)
    {
        inf=dialog->infdata();
        coildata = dialog->getUserInputData();
    }
    delete dialog;
}

//10功能码参数设置
void modbus_uart::on_regsetupbtn_clicked()
{
        dialogd = new DialogD(this);
        m_code = 0x10;
        int flag = dialogd->exec();
        if(!flag)
        {
            inf = dialogd->infdata();
            regdata = dialogd->getUserInputData();
        }
        delete dialogd;
}

//将读取的寄存器数据写入ini文件
void modbus_uart::WirteRegsDataToIni(quint16 startaddr, quint16 num,QVector<quint16> ba)
{
    for(quint16 i=0,k=startaddr;i<num;i++,k++)
    {
        //写入文件
        QString s = "Section" + QString::number(k+1) + "/regi";
        readseting->setValue(s,ba.at(i));
    }
}

//将读取的线圈数据写入ini文件
void modbus_uart::WirteCoilDataToIni(quint16 satrt, QString CoilData)
{
    //更新ini文件数据
    for(int j=0,k=satrt;j<CoilData.length();j++,k++)
    {
        QString s = "Section" + QString::number(k+1) + "/coil";
        quint8 coildata;
        if(CoilData.at(j)=='1')
        {
            coildata = 1;
        }
        else
        {
            coildata = 0;
        }
        readseting->setValue(s,coildata);
    }
    coildata.clear();
}
//解析报文
void modbus_uart::ParseResponseMessage(QByteArray responseMessage)
{
    //长度判断：最大长度、最小长度
    if(responseMessage.size() > 256)
    {
         showmsg("********异常报文********");
         showmsg("超出RTU最大报文长度！");
        return;
    }
    if(responseMessage.size() < 5)
    {
         showmsg("********异常报文********");
         showmsg("小于RTU最小报文长度！");
        return;
    }

    //CRC差错校验
    quint16 responseMessageCRC;
    responseMessageCRC = modbus_uart::crc16ForModbus(responseMessage,CRC_FLAG);
    quint16 CrcCheck;
    CrcCheck = BondTwoUint8ToUint16((quint8)responseMessage[responseMessage.size()-2],(quint8)responseMessage[responseMessage.size()-1]);
    if(CrcCheck != responseMessageCRC)
    {
        showmsg("********异常报文********");
        showmsg("回应报文校验码错误");
        return;
    }


    //从机地址是否正确
    if(requestMessage[0] != responseMessage[0])
    {
        showmsg("********异常报文********");
        showmsg("从机地址错误，与响应报文不一致");
        return;
    }


    //功能码是否合法
    quint8 responseMessageFuncCode;
    responseMessageFuncCode = (quint8)responseMessage[1];
    switch(responseMessageFuncCode)
    {
    case 0x01:
    case 0x03:
        analysis010(responseMessage);
        break;
    case 0x0f:
    case 0x10:
        analysis10F(responseMessage);
        break;

    case 0x81:
    case 0x83:
    case 0x90:
        RTUExceptionCodeJudge(responseMessage);
        break;
    default:
        showmsg("********异常报文********");
        showmsg("功能码非法，响应报文中功能码非法！");
        break;
    }
}

//01和03功能码解析
void modbus_uart::analysis010(QByteArray responseMessage)
{
    if(responseMessage.size()<=5)
    {
        showmsg("异常报文");
        showmsg("查询指令回应报文长度过短！");
        return;
    }

    //请求与响应功能码是否一致
    quint8 RequestMessageArrayFuncCode;
    RequestMessageArrayFuncCode = (quint8)requestMessage[1];
    if(RequestMessageArrayFuncCode != responseMessage.at(1))
    {
         showmsg("异常报文");
         showmsg("功能码错误，响应报文与请求报文功能码不一致");
         return;
    }



    //比对字节总数是否一致
    quint8 responseMessageDataNumber;
    responseMessageDataNumber = responseMessage.size() - 5;
    if((quint8)responseMessage[2] != responseMessageDataNumber)
    {
        showmsg("*异常报文");
        showmsg("报文字节字段异常");
        return;
    }
    //处理匹配的正常响应码
    QString dataObtained;
    quint16 startaddr = BondTwoUint8ToUint16(requestMessage.at(2),requestMessage.at(3));
    quint16 num = BondTwoUint8ToUint16(requestMessage.at(4),requestMessage.at(5));
    if(responseMessage.at(1)==1)
    {
        //取出所读的多个线圈，并显示，数据从第九位开始
        for(int i = 0; i < (quint8)responseMessage.at(2); i++)
        {
            //先转化为2进制字符串
            QString str = QString::number((quint8)responseMessage.at(3 + i),2);
            //再转化为2进制整形，由二进制整形转化为8位2进制字符串前面自动补0，从而保证8位
            str = QString("%1").arg((quint8)str.toInt(NULL,2),8,2,QChar('0'));
            //8bit字节倒转
            byteReverse(str);
            //添加到数据中
            dataObtained += str;
            coildata +=str;
        }
         wirtTablec(num,startaddr,dataObtained);
        //去除填充的0位，读出请求报文请求的线圈数
        dataObtained = dataObtained.left(num);
        //提示响应报文解析成功
        //消息窗口显示信息
        ReadCoilPackMsgToShow(startaddr,num,responseMessage);
        showmsg(dataObtained);
        WirteCoilDataToIni(startaddr,coildata);
    }
    else if(responseMessage.at(1)==3)
    {
        //取出所读的多个寄存器，并显示，数据从第9个字节开始
        for(int i = 0;i < (quint8)responseMessage.at(2); i += 2)
        {
            dataObtained += QString::number(BondTwoUint8ToUint16((quint8)responseMessage.at(3 + i),(quint8)responseMessage.at(4 + i)));
            bar.push_back(BondTwoUint8ToUint16((quint8)responseMessage.at(3 + i),(quint8)responseMessage.at(4 + i)));
            dataObtained += " ";
        }
         wirtTabler(num,startaddr,bar);
        //消息窗口显示信息
         ReadRegsPackMsgToShow(startaddr,num,responseMessage);
         showmsg(dataObtained);
         WirteRegsDataToIni(startaddr,num,bar);
    }


}

//报文寄存器读出提示
void modbus_uart::ReadCoilPackMsgToShow(quint16 startaddr,quint16 num,QByteArray msg)
{
    quint8 size = msg.size();
    QString msgs;
    for(quint8 i=0;i<size;i++)
    {
        //先转化为2进制字符串
        QString str = QString::number((quint8)msg.at(i),2);
        //再转化为2进制整形，由二进制整形转化为8位2进制字符串前面自动补0，从而保证8位
        str = QString("%1").arg((quint8)str.toInt(NULL,2),8,2,QChar('0'));
        //8bit字节倒转
        byteReverse(str);
        //添加到数据中
        msgs += str;
    }
    //去除填充的0位，读出请求报文请求的线圈数
    msgs = msgs.left(num);
    showmsg("成功读出线圈的数据\n");
    showmsg(QString("起始地址:%1").arg(startaddr)+"             "+QString("数量:%1\r\n").arg(num)+"\n");
    //showlogmsg(msgs+"\n");
    msgs.clear();
}

//报文寄存器数据读出提示
void modbus_uart::ReadRegsPackMsgToShow(quint16 startaddr,quint16 num,QByteArray msg)
{
    quint8 size = msg.size();
    QString msgs;
    quint16 data;
    for(quint8 i=0;i<size;i++)
    {
        QString str;
        data= msg.at(i);
        str = QString("%1 ").arg(data);
        msgs+=str;
    }
     showmsg("成功读出寄存器的数据\n");
     (QString("起始地址:%1").arg(startaddr)+"             "+QString("数量:%1\r\n").arg(num));
    msgs.clear();
    msg.clear();
}

//写入寄存器并提示信息
void modbus_uart::WirteRegsPackMsgToShow(quint16 startaddr, quint16 num,QByteArray msg)
{
    quint8 size = msg.size();
    QString msgs;
    quint16 data;
    for(quint8 i=0;i<size;i++)
    {
        QString str;
        data= (quint16)msg.at(i);
        str = QString("%1 ").arg(data);
        msgs+=str;
    }
//     showmsg("成功写入寄存器的数据\n");
//     showmsg(QString("起始地址:%1").arg(startaddr)+"             "+QString("数量:%1\r\n").arg(num));
     showmsg(msgs+"\n");
    msgs.clear();
}

//报文线圈数据写入提示
void modbus_uart::WirteCoilPackMsgToShow(quint16 startaddr, quint16 num, QByteArray msg)
{
    quint8 size = msg.size();
    QString msgs;
    for(quint8 i=0;i<size;i++)
    {
        //先转化为2进制字符串
        QString str = QString::number((quint8)msg.at(i),2);
        //再转化为2进制整形，由二进制整形转化为8位2进制字符串前面自动补0，从而保证8位
        str = QString("%1").arg((quint8)str.toInt(NULL,2),8,2,QChar('0'));
        //8bit字节倒转
        byteReverse(str);
        //添加到数据中
        msgs += str;
    }
    //去除填充的0位，读出请求报文请求的线圈数
    msgs = msgs.left(num);
//     showmsg("已写入线圈的数据\n");
//     showmsg(QString("起始地址:%1").arg(startaddr)+"             "+QString("数量:%1\r\n").arg(num));
     showmsg(msgs+"\n");
    msgs.clear();
}



//10和0F报文解析处理
void modbus_uart::analysis10F(QByteArray responseMessage)
{
    if(responseMessage.size()<8)
    {
        showmsg("--------------写指令回应报文长度错误！--------------");
    }
    //请求与响应的功能码是否一致
    quint8 RequestMessageArrayFuncCode;
    RequestMessageArrayFuncCode = (quint8)requestMessage[1];
    if(RequestMessageArrayFuncCode != responseMessage.at(1))
    {
        showmsg("-----------------功能码错误----------------------------");
        return;
    }

    //起始地址是否一致
    quint16 responseMessageBeginAddress;
    responseMessageBeginAddress=BondTwoUint8ToUint16((quint8)responseMessage[2],(quint8)responseMessage[3]);
    quint16 RequestMessageArrayBeginAddress;
    RequestMessageArrayBeginAddress=BondTwoUint8ToUint16((quint8)requestMessage[2],(quint8)requestMessage[3]);
    if(responseMessageBeginAddress != RequestMessageArrayBeginAddress)
    {
        showmsg("--------------------起始地址错误---------------------");
        return;
    }

    //查询数量是否一致
    quint16 responseMessageNumber;
    responseMessageNumber=BondTwoUint8ToUint16((quint8)responseMessage[4],(quint8)responseMessage[5]);
    quint16 RequestMessageArrayNumber;
    RequestMessageArrayNumber=BondTwoUint8ToUint16((quint8)requestMessage[4],(quint8)requestMessage[5]);
    if(responseMessageNumber != RequestMessageArrayNumber)
    {
        showmsg("------------------数量错误----------------------------");
        return;
    }

    if(responseMessage.at(1)==0x0f)
     {
           ui->display_TextEdit->append("已经写入线圈\n");
           ui->display_TextEdit->append("起时地址："+QString::number(responseMessageBeginAddress)+"                   "+"数量："+QString::number(responseMessageNumber)+"\n");

     }


    if(responseMessage.at(1)==0x10)
    {
        ui->display_TextEdit->append("已经写入寄存器\n");
        ui->display_TextEdit->append("起时地址："+QString::number(responseMessageBeginAddress)+"                   "+"数量："+QString::number(responseMessageNumber)+"\n");

    }


}


//异常功能码处理
void modbus_uart::RTUExceptionCodeJudge(QByteArray responseMessage)
{
    if(responseMessage.size()!=5)
    {
        showmsg("************异常报文************");
        showmsg("01，02，03异常回应报文长度不正确！");
        return;
    }
    QString exceptionCodePrompt;
    quint8 excCode = (quint8)responseMessage.at(2);
    switch (excCode)
    {
    case 0x01:
    {
        exceptionCodePrompt = "异常码为：01 非法功能";
        break;
    }
    case 0x02:
    {
        exceptionCodePrompt = "异常码为：02 非法数据地址";
        break;
    }
    case 0x03:
    {
        exceptionCodePrompt = "异常码为：03 非法数据值";
        break;
    }
    }
    //消息窗口显示信息
    showmsg(exceptionCodePrompt);
    return;
}

//超时重发
void modbus_uart::timeout_handler()
{
    timeout++;
    if(timeout<3)
    {
        QDateTime current_date_time =QDateTime::currentDateTime();
        QString current_date =current_date_time.toString("yyyy.MM.dd hh:mm:ss ddd");
        ui->display_TextEdit->append("从站未回应，进行超时处理"+current_date);
        ui->display_TextEdit->append("第"+ QString::number(timeout)+"次向从站重新报文\n");
        //senddatetwice(resenddata);
    }
}

//保存历史数据
void modbus_uart::on_historyBtn_clicked()
{
    QString fileName=QFileDialog::getSaveFileName(this,"Save File",QDir::currentPath());
    if(fileName.isEmpty())
       {
           QMessageBox::information(this,"Error Message","请选择文件的路径");
           return;
       }

      QFile *file=new QFile;
      file->setFileName(fileName);
         bool ok=file->open(QIODevice::WriteOnly);
         if(ok)
         {
             QTextStream out(file);
             out<<ui->display_TextEdit->toPlainText();
             file->close();
             delete file;
         }
         else
           {
               QMessageBox::information(this,"Error Messaage","File Save Error"+file->errorString());
               return;
           }
}


